import { useCallback, useEffect, useState } from "react";
import './index.css'
import classname from "classnames";
import { useWorkspace } from "../../workspace";
import { config } from "../../utils/config";
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'
import { fetchDigitalAsset } from '@metaplex-foundation/mpl-token-metadata'
import { AnchorError } from "@coral-xyz/anchor/dist/cjs/error";
import { PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram } from "@solana/web3.js";
import { ASSOCIATED_PROGRAM_ID, associatedAddress } from "@coral-xyz/anchor/dist/cjs/utils/token";
import BN from "bn.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import * as anchor from "@coral-xyz/anchor";
import { Success, Error, Close } from '../../../components/dialog/message'
import { MyBox } from '../../../components/tab/mybox'

import { NoData } from '../../../components/nodata/index'
import { fetchNFTImage } from "../../utils/bignum";
import { Loading } from '../../../components/loading/index'
interface NftData {
  nft_id: string;
  nft_name: string;
  nft_symbol: string;
  nft_img: string;
  timestamp:string;
  saleinfo:string;
}

const collectionMint = config.collectionMint;
//const metadata_program_address = config.metadata_program_address;
export default function HomePage() {
  const [tab, setTab] = useState(0);
  const [list, setList] = useState<NftData[]>([]);
  const work = useWorkspace();
  const [ showSuccess, setShowSuccess ] = useState('')
  const [ showError, setShowError ] = useState('')
  const [ showClose, setShowClose ] = useState('')
  const [ isLoad, setIsLoad] = useState(false)
  const [ showLoading, setShowLoading] = useState(false)


  const tabFn = (tabIndex: number) => {
    setTab(tabIndex);
  }


  const showToastSuccess = (text: string) =>{
    setShowSuccess(text)
    setTimeout(() =>{
      setShowSuccess('')
    },2000)
  }
  const showToastError = (text: string) =>{
    setShowError(text)
    setTimeout(() =>{
      setShowError('')
    },2000)
  }
  const showToastClose = (text: string) =>{
    setShowClose(text)
    setTimeout(() =>{
      setShowClose('')
    },2000)
  }
  const getData = useCallback(async () => {
    try {
      if (work && work.wallet) {
        const { connection, program, wallet, provider } = work;
        const umi = createUmi(config.rpc).use(mplTokenMetadata());
        const userString = wallet.publicKey.toString();

        let filteredResults: NftData[] = [];

        if (tab === 1) {
          const filters = [{
            memcmp: {
              offset: 8, // owner字段在account数据中的起始位置
              bytes: userString,
            },
          }];

          const stakeInfoAccounts = await program.account.nftSale.all(filters);
          setIsLoad(true);
          console.log('stakeInfoAccounts', stakeInfoAccounts);
          if(stakeInfoAccounts){

            for (const accountInfo of stakeInfoAccounts) {

              const nft_id = accountInfo.account.mint;
              const stake = accountInfo.publicKey;
              const timestamp = accountInfo.account.timestamp;

              console.log('nft_mint:', nft_id.toBase58());
              console.log('stake:', stake.toBase58());
              console.log('time:', timestamp.toString());

              const nft = await fetchDigitalAsset(umi, nft_id);
              console.log(nft);

              // Note: You should ideally extract the real properties from the NFT object
              const nft_name = nft.metadata.name;
              const nft_symbol = nft.metadata.name;
              const uri = nft.metadata.uri;
              //fertch uri
              //const alternativeUri = uri.replace('https://ipfs.io', 'https://cloudflare-ipfs.com');

              let nft_img = '';
              try {
                nft_img = await fetchNFTImage(uri);
                //console.log('Image:', nft_img);
              } catch (error) {
                  console.error('get img error :', error);
              }
              console.log('NFT Image:', nft_img);
              filteredResults.push({
                nft_id: nft_id.toBase58(),
                nft_name: nft_name,
                nft_img: nft_img,
                nft_symbol: nft_symbol,
                saleinfo:stake.toBase58(),
                timestamp:timestamp.toString(),
              });
            }

          }

        } else if(tab === 0){
          const url = config.heliusrpc;
          const response = await fetch(url, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              jsonrpc: '2.0',
              id: 'my-id',
              method: 'searchAssets',
              params: {
                ownerAddress: userString,
                grouping: ['collection', collectionMint],
                page: 1,
                limit: 1000,
              },
            }),
          });

          const { result } = await response.json();
          setIsLoad(true);
          console.log(result);
          if (result.total) {
            filteredResults = result.items.map((nft: any) => {
              const nft_img = nft.content.links.image;
              const nft_id = nft.id;
              const nft_name = nft.content.metadata.name;
              const nft_symbol = nft.content.metadata.symbol;

              return {
                nft_id: nft_id,
                nft_name: nft_name,
                nft_symbol: nft_symbol,
                nft_img: nft_img,
                timestamp:"",
                saleinfo:"",

              };
            });
          }
        }

        setList(filteredResults);
      }
    } catch (error) {
      showToastError('fetch data error')
      if (error instanceof AnchorError) {
        const code = error.error.errorCode.code;
        const number = error.error.errorCode.number;
        const message = error.error.errorMessage;

        console.error('捕获到的错误: ', code, number, message);
      } else {

        console.error('未知错误: ', error);
      }
    }
  }, [work, tab]);

  useEffect(() => {
    getData();
  }, [getData]);

  const handle = async (nft: NftData) => {
    setShowLoading(true)
    try {
      if (work && work.wallet) {

        const { connection, program, wallet, provider } = work;
        if (tab === 0) {
          // Perform operation for staked NFTs


          //console.log(`Extracting staked NFT with id: ${nft_id}`);
          //const METADATA_PROGRAM = new PublicKey(metadata_program_address);

          //组装数据
          const timestamp = Math.floor(new Date().getTime() / 1000);
          const user = provider.wallet.publicKey;

          const nft_mint = new PublicKey(nft.nft_id);//预售得到的nft mint地址
          const user_token_account =  associatedAddress({
          mint: nft_mint,
          owner: user
          });
          const plat_token_account = PublicKey.findProgramAddressSync([Buffer.from("plat_token"), nft_mint.toBuffer()], program.programId)[0];
          const saleinfo = anchor.web3.PublicKey.findProgramAddressSync([new BN(timestamp).toArrayLike(Buffer, "le", 8)], program.programId)[0];
          const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];
          const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];

          try {

              const tx = await program.methods
                  .pledgeNft(new BN(timestamp))
                  .accounts({
                      user: user,
                      nftMint: nft_mint,
                      userTokenAccount: user_token_account,
                      platTokenAccount: plat_token_account,
                      saleinfo: saleinfo,
                      pledgePool: pledge_pool,
                      pledgeUser: pledge_user,
                      systemProgram: SystemProgram.programId,
                      tokenProgram: TOKEN_PROGRAM_ID,
                      associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
                      rent: SYSVAR_RENT_PUBKEY,
                  })
                  .signers([])
                  .rpc();

                  console.log("Your transaction signature", tx);
                  showToastSuccess('Stake Success');
                  setShowLoading(false)
          } catch (error) {

              if (error instanceof AnchorError) {
                  showToastError("Stake Fail");

                  const code = error.error.errorCode.code ;
                  const number = error.error.errorCode.number ;
                  const  message = error.error.errorMessage;
                  setShowLoading(false)
                  console.error('捕获到的错误: ', code,number,message);
                  // 在这里处理错误，例如显示错误消息给用户
              } else {
                  // 处理其他类型的错误
                  setShowLoading(false)
                  console.error('未知错误: ', error);
              }
            }

          // Example operation: remove NFT from list
          setList((prevList) => prevList.filter((item) => item.nft_id !== nft.nft_id));

          // Add your specific logic for staked NFTs here

        } else if(tab === 1){
          // Perform operation for my NFTs
          //console.log(`Extracting my NFT with id: ${nft_id}`);


          const user = provider.wallet.publicKey;
          const nft_mint = new PublicKey(nft.nft_id);//预售得到的nft mint地址
          const user_token_account =  associatedAddress({
          mint: nft_mint,
          owner: user
          });
          const timestamp = nft.timestamp;
          const saleinfo = new PublicKey(nft.saleinfo);
          const plat_token_account = PublicKey.findProgramAddressSync([Buffer.from("plat_token"), nft_mint.toBuffer()], program.programId)[0];
          const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];
          const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];

          try {

                  const tx = await program.methods
                  .unpledgeNft(new BN(timestamp))
                  .accounts({
                      user: user,
                      nftMint: nft_mint,
                      userTokenAccount: user_token_account,
                      platTokenAccount: plat_token_account,
                      saleinfo: saleinfo,
                      pledgePool: pledge_pool,
                      pledgeUser: pledge_user,
                      systemProgram: SystemProgram.programId,
                      tokenProgram: TOKEN_PROGRAM_ID,
                      associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
                      rent: SYSVAR_RENT_PUBKEY,
                  })
                  .signers([])
                  .rpc();

                  console.log("Your transaction signature", tx);
                  showToastSuccess('UnStake Success');
                  setShowLoading(false)
          } catch (error) {

              if (error instanceof AnchorError) {

                  showToastError("UnStake Fail");
                  const code = error.error.errorCode.code ;
                  const number = error.error.errorCode.number ;
                  const  message = error.error.errorMessage;
                  setShowLoading(false)
                  console.error('捕获到的错误: ', code,number,message);
                  // 在这里处理错误，例如显示错误消息给用户
              } else {
                setShowLoading(false)
                // 处理其他类型的错误
                console.error('未知错误: ', error);
              }
            }

          // Example operation: remove NFT from list
          setList((prevList) => prevList.filter((item) => item.nft_id !== nft.nft_id));

          // Add your specific logic for my NFTs here
        }
      }else{
        const walletBtn:any = document.querySelector('.wallet-adapter-button')
        console.log(walletBtn)
        setShowLoading(false)
        walletBtn.click()
      }
    } catch (error) {
      setShowLoading(false)
      console.error('Failed to extract NFT:', error);
    }
  };

  return (
    <div className="grid-width">
      <div className="nft">
        <div className="nft-tab">
          <div onClick={() => tabFn(0)} className={classname({
            "nft-tab-item": true,
            "nft-tab-active": tab === 0,
          })}>My NFT</div>
          <div onClick={() => tabFn(1)} className={classname({
            "nft-tab-item": true,
            "nft-tab-active": tab === 1,
          })}>Stacked NFT</div>
          <div onClick={() => tabFn(2)} className={classname({
            "nft-tab-item": true,
            "nft-tab-active": tab === 2,
          })}>My Box</div>
        </div>
        {
          tab === 2 ?
          <MyBox/>
          :
          <div className="nft-list">
            {list.map((nft) => (
              <div className="nft-list-item" key={nft.nft_id}>
                <img className="nft-list-thumb" src={nft.nft_img} alt={nft.nft_symbol} />
                <div className="nft-list-text">{nft.nft_name}</div>
                <div className="nft-list-text">{nft.nft_symbol}</div>
                <div onClick={() => handle(nft)} className="nft-list-btn">
                  {
                    ['stack','unstack'][tab]
                  }
                </div>
              </div>
            ))}
            {

              isLoad && list.length === 0 && <NoData></NoData>
            }
          </div>
        }
      </div>
      <div className="footer">
        <img className="footer-icon1" src="../../../assets/monery.png" alt="" />
        <img className="footer-icon2" src="../../../assets/kefu.png" alt="" />
      </div>
      {
        showSuccess && <Success text={showSuccess}/>
      }
      {
        showError && <Error text={showSuccess}/>
      }
      {
        showLoading && <Loading/>
      }
      {
        showClose && <Close  text={showSuccess} onCancel={() =>{
          setShowClose('')
        }}/>
      }
    </div>
  );
}
